
package com.lee.tree; 
 
 
import com.lee.logger.Logger; 
import lombok.Data; 
 
import java.util.*; 
 
@Data 
public class FPTree { 
    private FPNode root;
    private Map<String, TwoTuple> routes;
    private Map<FPNode,FPNode> route;
    public FPTree(){
        this.setRoot(new FPNode(this,null,null));
        this.setRoutes(new HashMap<>());
    }
 
    public void add(List<String> transaction){
        FPNode point = this.getRoot();
        for(String item:transaction){
            FPNode nextPoint = point.search(item);
            if (nextPoint != null){
                nextPoint.increment();
            }else {
                nextPoint = new FPNode(this,item);
                point.add(nextPoint);
                this.updateRoute(nextPoint);
            }
            point = nextPoint;
        }
    }
 
    public void updateRoute(FPNode point){
        if(this.getRoutes().containsKey(point.getItem())){
            TwoTuple<FPNode,FPNode> route = this.getRoutes().get(point.getItem());
            route.second.setNeighbor(point);
            TwoTuple<FPNode,FPNode> neighborRoute = new TwoTuple<>(route.first,point);
            this.getRoutes().put(point.getItem(),neighborRoute);
 
        } else {
            TwoTuple<FPNode,FPNode> neighborRoute = new TwoTuple<>(point,point);
            this.getRoutes().put(point.getItem(),neighborRoute);
        }
 
    }
 
    //routes 是一个链表（数据类型：map）
    //将map类型的routes转换为list，key value 变为二元组
    public List<TwoTuple<String,List<FPNode>>> getItems(){
        List<TwoTuple<String,List<FPNode>>> items = new ArrayList<>();
        for(String item:getRoutes().keySet()){
            items.add(new TwoTuple(item,this.getNodes(item)));
        }
        return items;
    }
 
    //routes 是一个链表（数据类型：map）,routes的value值是一个元组，元组第一项是链表的第一个结点，第二项是链表的最后一个结点
    // A : N(A1),N(A1) -> N(A2)
    // B : N(B1),N(B1)
    // C : N(C1),N(C1) -> N(C2) -> N(C3)
    //getNodes方法是找到item的所有元素
    private List<FPNode> getNodes(String item){
        List<FPNode> nodes  = new ArrayList<>();
        TwoTuple<FPNode,FPNode> route = this.getRoutes().get(item);
 
        FPNode node  = route.first;
        while(node!=null){
            nodes.add(node);
            node = node.getNeighbor();
        }
        return nodes;
 
    }
 
    private List<FPNode> collectPath(FPNode node){
        List<FPNode> path = new ArrayList<>();
        while (node != null && !node.isRoot()){
            path.add(node);
            node = node.getParent();
        }
        Collections.reverse(path);
        return path;
    }
    public List<List<FPNode>> prefixPaths(String item){
        List<List<FPNode>> paths = new ArrayList<>();
        for(FPNode node:this.getNodes(item)){
            List<FPNode> path = collectPath(node);
            paths.add(path);
        }
        return paths;
    }
    public void inspect(){
        Logger.info("Tree:");
        this.getRoot().inspect(1);
//        Logger.info("Routes:");
//        List<TwoTuple<String, List<FPNode>>> items = this.getItems();
//        for (int i=0;i<items.size();i++){
//            String item = items.get(i).first;
//            List<FPNode> nodes = items.get(i).second;
//            Logger.info(String.format("    %s",item));
//            for(FPNode node:nodes){
//                Logger.info(String.format("        %s",node));
//            }
// 
//        }
    }
 
 
    @Override
    public String toString() {
        return "FPTree{}";
    }
} 
